package cus.area.util;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cus.area.util.entity.ParseAreaResult;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 地址解析类,解析手机,座机,姓名,地址
 */
public class ParseAddress {

    private static Set<String> excludeKeys = Stream.of("发件人", "收货地址", "收货人", "收件人", "收货", "手机号码", "邮编", "电話", "电话", "所在地区", "详细地址", "地址", "：", ":", "；", ";", "，", ",", "。", "、").collect(Collectors.toSet());

    /**
     * 解析地址,解析结果为[省,市,区,姓名,手机号,座机号,邮编]的集合,根据相关性进行排序,越靠前结果越符合预期
     * @param address
     * @param parseAll
     * @return
     */
    public static List<ParseAreaResult> parse(String address, boolean parseAll) {
        ParseAreaResult extraResult = new ParseAreaResult();
        //替换特殊字符,解析手机,座机,邮编,格式化多余空格
        address = replace(address);
        address = parseMobile(address, extraResult);
        address = parsePhone(address, extraResult);
        address = parseZipCode(address, extraResult);
        address = address.replaceAll(" {2,}", " ");

        //解析地址
        List<ParseAreaResult> results = ParseArea.parse(address, parseAll);

        //将解析的地址结果重新解析一次名称
        if (CollectionUtil.isNotEmpty(results)) {
            results.stream().forEach(r -> {
                r.setMobile(extraResult.getMobile());
                r.setPhone(extraResult.getPhone());
                r.setZipCode(extraResult.getZipCode());
                parseName(r, 11);
            });
        } else {
            parseName(extraResult, 11);
            results.add(extraResult);
        }
        return results;
    }

    /**
     * 替换无效字符
     */
    private static String replace(String address) {
        for (String key : excludeKeys) {
            address = address.replaceAll(key, " ");
        }
        return address.replaceAll("\\r\\n", " ").replaceAll("\\n", " ").replace("\\t", " ").replace(" {2,}", " ").replaceAll("(\\d{3})-(\\d{4})-(\\d{4})", "$1$2$3").replace("(\\d{3}) (\\d{4}) (\\d{4})", "$1$2$3");
    }

    /**
     * 提取手机号码
     */
    private static String parseMobile(String address, ParseAreaResult result) {
        String mobile = ReUtil.get(AreaUtils.mobile, address, 0);
        if (StrUtil.isNotEmpty(mobile)) {
            result.setMobile(mobile);
            return address.replaceAll(mobile, " ");
        }
        return address;
    }

    /**
     * 提取座机号码
     */
    private static String parsePhone(String address, ParseAreaResult result) {
        String phone = ReUtil.get(AreaUtils.phone, address, 0);
        if (StrUtil.isNotEmpty(phone)) {
            result.setPhone(phone);
            return address.replaceAll(phone, " ");
        }
        return address;
    }

    /**
     * 提取邮编
     */
    private static String parseZipCode(String address, ParseAreaResult result) {
        String zipCode = ReUtil.get(AreaUtils.zipCode, address, 0);
        if (StrUtil.isNotEmpty(zipCode)) {
            result.setZipCode(zipCode);
            return address.replaceAll(zipCode, " ");
        }
        return address;
    }

    /**
     * 提取名称
     */
    private static void parseName(ParseAreaResult result, int maxLen) {
        //设置result
        if (StrUtil.isEmpty(result.getName())) {
            List<String> list = Stream.of(result.getDetails().split(" ")).collect(Collectors.toCollection(ArrayList::new));
            AtomicReference<String> name = new AtomicReference<>("");
            AtomicInteger index = new AtomicInteger(-1);
            list.stream().forEach(s -> {
                index.addAndGet(1);
                if (StrUtil.isNotEmpty(s) && s.length() < maxLen) {
                    if (StrUtil.isEmpty(name.get()) || name.get().length() > s.length()) {
                        name.set(s);
                    }
                }
            });

            if (StrUtil.isNotEmpty(name.get())) {
                result.setName(name.get().trim());
                list.remove(index.get());
                result.setDetails(list.stream().collect(Collectors.joining(" ")));
            }
        }
    }
}
